package cc.wanforme.st.server.util;

import cc.wanforme.fsync.client.ClientProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;

/**
 * server 跟 client 通信的http工具
 */
@Service
public class HttpTool {
    private RestTemplate restTemplate;
    private RestTemplate uploadRestTemplate;
    private ClientProperty clientProperty;

    private HttpHeaders headers() {
        HttpHeaders map = new HttpHeaders();
        map.add("content-type", MediaType.APPLICATION_JSON_VALUE);
        if(StringUtils.hasText(clientProperty.getHttpHeader())) {
            map.add(clientProperty.getHttpHeader(), clientProperty.getHttpValue());
        }
        return map;
    }

    // 请求任意接口，无url参数，返回字符串
    public String post(String interf, Object body) {
        return post2(interf, body);
    }
    // 请求任意接口，有rul参数，返回字符串
    public String post2(String interf, Object body, Object... uriParams) {
        HttpEntity<?> httpEntity = new HttpEntity<>(body, headers());
        return restTemplate.postForObject(interf, httpEntity, String.class, uriParams);
    }

    // 请求任意接口，无url参数，返回指定实体
    public <T> T post(String interf, Object body, Class<T> resultType) {
        return post2(interf, body, resultType);
    }
    // 请求任意接口，有url参数，返回指定实体
    public <T> T post2(String interf, Object body, Class<T> resultType, Object... uriParams) {
        HttpEntity<?> httpEntity = new HttpEntity<>(body, headers());
        return restTemplate.postForObject(interf, httpEntity, resultType, uriParams);
    }

    public <T> T post(String interf, Object body, ParameterizedTypeReference<T> type, Object... uriParams) {
        HttpEntity<?> httpEntity = new HttpEntity<>(body, headers());
        return restTemplate.exchange(interf, HttpMethod.POST, httpEntity, type, uriParams).getBody();
    }

    /**
     * post 上传文件 <br/>
     * 参考：https://blog.csdn.net/loveLifeLoveCoding/article/details/128317783
     * @param interf 接口
     * @param savePath 文件的保存路径
     * @param resource 文件流
     * @param type 返回类型
     */
    public <T> T uploadFile(String interf, String savePath, Resource resource, TypeReference<T> type)
            throws IOException {
        HttpHeaders headersss = headers();
        headersss.setContentType(MediaType.MULTIPART_FORM_DATA); // 重置 content-type

        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>(1);
        params.add("file", resource); // 文件
        params.add("path", encParam(savePath)); // 保存文件的路径
        params.add("modifyTime", encParam(resource.lastModified()+""));

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(params, headersss);

        // 原来的方式
        String res = restTemplate.postForObject(interf, httpEntity, String.class);
        return SimpleJackson.toAny(res, type);
    }

    /**
     * post 上传文件 <br/>
     * 参考：https://blog.csdn.net/loveLifeLoveCoding/article/details/128317783
     * @param interf 接口
     * @param savePath 文件的保存路径
     * @param resource 文件流
     * @param type 返回类型
     */
    public <T> T uploadFileWithProgress(String interf, String savePath, Resource resource,
                                        TypeReference<T> type) throws IOException {
        HttpHeaders headersss = headers();
        headersss.setContentType(MediaType.MULTIPART_FORM_DATA); // 重置 content-type

        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>(1);
        params.add("file", resource); // 文件
        params.add("path", encParam(savePath)); // 保存文件的路径
        params.add("modifyTime", encParam(resource.lastModified()+""));

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(params, headersss);

        // 上传
        String res = uploadRestTemplate.postForObject(interf, httpEntity, String.class);
        return SimpleJackson.toAny(res, type);
    }

    public static String encParam(String val) {
        return URLEncoder.encode(val, Charset.forName("utf-8"));
    }
    public static String decParam(String val) {
        return URLDecoder.decode(val, Charset.forName("utf-8"));
    }

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    @Autowired
    public void setClientProperty(ClientProperty clientProperty) {
        this.clientProperty = clientProperty;
    }
    @Autowired
    @Qualifier("uploadRestTemplate")
    public void setUploadRestTemplate(RestTemplate uploadRestTemplate) {
        this.uploadRestTemplate = uploadRestTemplate;
    }

}
